#pragma once

#include "libs/httplib.h"
#include "libs/easylog.h"
#include "except.hpp"

namespace pharmacy_server
{
    class server
    {
    public:
        using bus_type = bool;
        using business = std::function<void(const httplib::Request&, httplib::Response&)>;
        using tuples_of_business = std::vector<std::tuple<bus_type, std::string, server::business>>;


        static server& instance(int port)
        {
            static server svr(port);
            return svr;
        }

    private:
        server(int port)
            : _ip("0.0.0.0")
            , _port(port)
        {
        }

        server(const server&) = delete;
        server& operator=(const server&) = delete;

    public:
        void bus_resgister(const tuples_of_business& businesses)
        {
            for (const auto& bus : businesses)
            {
                _register(std::get<0>(bus), std::get<1>(bus), std::get<2>(bus));
            }
        }

        void start()
        {
            easylog::info("http server started on {}", _port);

            if (!_svr.listen(_ip, _port))
            {
                easylog::error("http server start failed on {}:{}", _ip, _port);
                throw server_except("http server start failed");
            }
        }

    private:
        void _register(bus_type type, const std::string& name, const business& bus)
        {
            if (type == get)
            {
                _svr.Get(name, bus);
            }
            else if (type == post)
            {
                _svr.Post(name, bus);
            }
            else
            {
                easylog::error("bus_register failed, bus_type is invalid");
                throw server_except("bus_register failed, bus_type is invalid");
            }
        }

    public:
        static const bus_type get;
        static const bus_type post;

    private:
        std::string _ip;
        uint16_t _port;
        httplib::Server _svr;

    };
}
